package it.uniroma2.cloud.util;

import it.uniroma2.cloud.util.PropertiesMap.CloudProviderProperty;

import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;

import org.jclouds.aws.domain.Region;
import org.jclouds.compute.ComputeService;
import org.jclouds.compute.RunScriptOnNodesException;
import org.jclouds.compute.domain.NodeMetadata;
import org.jclouds.compute.domain.NodeMetadataBuilder;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.domain.TemplateBuilder;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.ec2.compute.options.EC2TemplateOptions;
import org.jclouds.ec2.domain.InstanceType;
import org.jclouds.io.Payloads;
import org.jclouds.scriptbuilder.domain.Statements;
import org.jclouds.ssh.SshClient;

import com.google.common.base.Charsets;
import com.google.common.io.Files;

public class AWSProviderHelper extends AbstractProviderHelper implements
		ProviderHelper {

	private static String DEFAULT_REGION = Region.US_EAST_1;
	private static final PropertiesMap p = PropertiesMap.getInstance();
	private static AWSProviderHelper instance = null;

	private AWSProviderHelper() {
	}

	public static AWSProviderHelper getInstance() {
		if (instance == null) {
			instance = new AWSProviderHelper();
		}
		return instance;
	}

	@Override
	public LoginCredentials getLoginCredentials() {
		LoginCredentials lc = null;
		try {
			lc = getLoginCredentials(DEFAULT_REGION);
		} catch (IOException e) {
			e.printStackTrace();
		}
		return lc;
	}

	@Override
	public Template getTemplate(ComputeService computeService) {
		return getTemplate(computeService, DEFAULT_REGION);
	}

	public Template getTemplate(ComputeService computeService, String region) {
		TemplateBuilder templateBuilder = computeService.templateBuilder();
		Template t = null;
		String awsRegion = null;
		String imageId = null;
		String keyName = null;
		if (region == DEFAULT_REGION) {
			awsRegion = DEFAULT_REGION;
			imageId = p.get(CloudProviderProperty.AWS_DEFAULT_IMAGE);
			keyName = p.get(CloudProviderProperty.AWS_KEY_NAME);
		} else if (region == Region.EU_WEST_1) {
			awsRegion = region;
			imageId = p.get(CloudProviderProperty.AWS_DEFAULT_IMAGE_EU_WEST);
			keyName = p.get(CloudProviderProperty.AWS_KEY_NAME_EU_WEST);
		} else
			return null;

		try {
			t = templateBuilder
					.imageId(awsRegion + "/" + imageId)
					.hardwareId(InstanceType.M1_MEDIUM)
					.options(
							EC2TemplateOptions.Builder
									.keyPair(keyName)
									.overrideLoginCredentials(
											getLoginCredentials(awsRegion))
									.inboundPorts(getPortsToBeOpened()))
					.build();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return t;
	}

	public LoginCredentials getLoginCredentials(String region)
			throws IOException {
		String keyPath = null;
		if (region == DEFAULT_REGION) {
			keyPath = p.get(CloudProviderProperty.AWS_KEY_PATH);
		} else if (region == Region.EU_WEST_1) {
			keyPath = p.get(CloudProviderProperty.AWS_KEY_PATH_EU_WEST);
		} else
			keyPath = null;

		String privateKey = Files.toString(new File(keyPath), Charsets.UTF_8);
		return LoginCredentials.builder()
				.user(p.get(CloudProviderProperty.AWS_AMI_USER))
				.privateKey(privateKey).authenticateSudo(true).build();

	}

//	@Override
//	protected String getChefURL() {
//		PropertiesMap p = PropertiesMap.getInstance();
//		return p.get(CloudProviderProperty.CHEF_SERVER_AWS);
//	}

	@Override
	public void updateLoadBalancer(ComputeService computeService,
			Collection<String> ips) {
		String lbId = p.get(CloudProviderProperty.AWS_LB_INSTANCE_ID);
		NodeMetadata lbNodeMetadata = computeService.getNodeMetadata(lbId);

		StringBuffer s = new StringBuffer();
		s.append("upstream backend {\n");
		for (String ip : ips) {
			s.append("  server ");
			s.append(ip);
			s.append(":8080;\n");
		}
		s.append("}\nserver {\n  location / {\n    proxy_pass  http://backend;\n  }\n}\n");

		SshClient client = computeService
				.getContext()
				.utils()
				.sshForNode()
				.apply(NodeMetadataBuilder.fromNodeMetadata(lbNodeMetadata)
						.credentials(getLoginCredentials()).build());
		try {
			client.connect();
			client.put("/home/ubuntu/newNginx",
					Payloads.newStringPayload(s.toString()));

			runScriptOnInstance(
					computeService,
					lbId,
					Statements
							.exec("cp /home/ubuntu/newNginx /etc/nginx/sites-enabled/awslb"));
			runScriptOnInstance(computeService, lbId,
					Statements.exec("kill -HUP `cat /var/run/nginx.pid`")); // OPPURE
			// "service nginx reload"
		} catch (RunScriptOnNodesException e) {
			e.printStackTrace();
		} finally {
			if (client != null)
				client.disconnect();
		}
	}
	
	@Override
	public String getLoadBalancerAddress(ComputeService computeService) {
		Iterable<? extends NodeMetadata> nodes = listRunningNodesInGroup(computeService, "loadbalancer");
		Iterator<? extends NodeMetadata> nodeIt = nodes.iterator();
		String ret = null;
		while (nodeIt.hasNext()) {
			NodeMetadata node = nodeIt.next();
			ret = node.getPublicAddresses().iterator().next();
		}
		return ret;
	}

	@Override
	public String getReachableIp(ComputeService computeService,
			NodeMetadata node) {
		return node.getPublicAddresses().iterator().next();
	}
	
	public NodeMetadata getNodeByReachableIp(ComputeService computeService,
			String groupName, String ip) {
		Iterable<? extends NodeMetadata> nodes = listRunningNodesInGroup(
				computeService, groupName);
		Iterator<? extends NodeMetadata> nodeIt = nodes.iterator();
		NodeMetadata ret = null;
		while (nodeIt.hasNext()) {
			NodeMetadata node = nodeIt.next();
			String ipNode = node.getPublicAddresses().iterator().next();
			if (ip.equals(ipNode)) {
				ret = node;
				break;
			}
		}
		return ret;
	}


}
